import Axios, { AxiosInstance, AxiosRequestConfig } from "axios";
import {
  resultType,
  PureHttpError,
  RequestMethods,
  PureHttpResponse,
  PureHttpRequestConfig
} from "./types.d";
import qs from "qs";
import NProgress from "../progress";
import { loadEnv } from "@build/index";
import { getRefreshToken, gotoLogin } from "/@/utils/auth";
import { useUserStoreHook } from "/@/store/modules/user";
import { ElMessage } from 'element-plus'
import { isArray } from '@pureadmin/utils'
import { $t } from "/@/plugins/i18n";
import { isObject } from "lodash-es";
import { router } from '/@/router'

// 加载环境变量 VITE_PROXY_DOMAIN
const { VITE_PROXY_DOMAIN_REAL } = loadEnv();

// 相关配置请参考：www.axios-js.com/zh-cn/docs/#axios-request-config-1
const defaultConfig: AxiosRequestConfig = {
  baseURL: VITE_PROXY_DOMAIN_REAL,
  // 当前使用mock模拟请求，将baseURL制空，如果你的环境用到了http请求，请删除下面的baseURL启用上面的baseURL，并将11行、16行代码注释取消
  // baseURL: "",
  timeout: import.meta.env.DEV ? 10000000000 : 10000,
  headers: {
    Accept: "*/*",
    "Content-Type": "application/json",
    // "X-Requested-With": "XMLHttpRequest"
  },
  withCredentials: false,
  // 数组格式参数序列化
  paramsSerializer: params => qs.stringify(params, { indices: false })
};

class PureHttp {
  constructor() {
    this.httpInterceptorsRequest();
    this.httpInterceptorsResponse();
  }
  /** 初始化配置对象 */
  private static initConfig: PureHttpRequestConfig = {};

  /** 保存当前Axios实例对象 */
  private static axiosInstance: AxiosInstance = Axios.create(defaultConfig);

  /** 请求拦截 */
  private httpInterceptorsRequest(): void {
    PureHttp.axiosInstance.interceptors.request.use(
      (config: PureHttpRequestConfig) => {
        const $config = config;
        // 开启进度条动画
        NProgress.start();
        // 优先判断post/get等方法是否传入回掉，否则执行初始化设置等回掉
        if (typeof config.beforeRequestCallback === "function") {
          config.beforeRequestCallback($config);
          return $config;
        }
        if (PureHttp.initConfig.beforeRequestCallback) {
          PureHttp.initConfig.beforeRequestCallback($config);
          return $config;
        }

        const userStore = useUserStoreHook();
        if (userStore.token) {
          config.headers["Authorization"] = "Bearer " + userStore.token;

          if (userStore.isTokenExp()) {
            config.headers["X-Authorization"] = "Bearer " + getRefreshToken()
          }
        }

        return $config;
      },
      error => {
        ElMessage.error(error.message)
        return Promise.reject(error);
      }
    );
  }

  /** 响应拦截 */
  private httpInterceptorsResponse(): void {
    const instance = PureHttp.axiosInstance;
    instance.interceptors.response.use(
      (response: PureHttpResponse) => {
        var status = response.status;
        const $config = response.config;
        // 关闭进度条动画
        NProgress.done();
        // 优先判断post/get等方法是否传入回掉，否则执行初始化设置等回掉
        if (typeof $config.beforeResponseCallback === "function") {
          $config.beforeResponseCallback(response);
          return response.data;
        }
        if (PureHttp.initConfig.beforeResponseCallback) {
          PureHttp.initConfig.beforeResponseCallback(response);
          return response.data;
        }

        try {
          // 处理未进行规范化处理的
          if (status >= 400) {
            throw new Error(response.statusText || "Request Error.");
          }

          const resData = response.data;

          // 处理规范化结果错误
          if (resData && resData.hasOwnProperty("errors") && resData.errors) {
            let errorMessage = "Request Error."

            if (typeof resData.errors === 'string') {
              errorMessage = resData.errors;
            }

            if (isArray(resData.errors)) {
              errorMessage = resData.errors.join('\r\n')
            }

            if (isObject(resData.errors)) {
              errorMessage = Object.keys(resData.errors).map(k => `${k}：${resData.errors[k]}`).join('\r\n')
            }

            throw new Error(errorMessage);
          }

          // 读取响应报文头 token 信息
          var accessToken = response.headers['access-token'];
          var refreshAccessToken = response.headers['x-access-token'];

          if (accessToken && refreshAccessToken) {
            const userStore = useUserStoreHook();

            userStore.setToken(accessToken)
            userStore.setRefreshToken(refreshAccessToken)
          }


          return response.data;
        } catch (err) {
          ElMessage.error(err.message)

          if (response.data?.statusCode === 401) {
            const userStore = useUserStoreHook();
            userStore.logOut()
            router.push({
              path: '/login'
            })
          }
          return Promise.reject(err)
        }
      },
      (error: PureHttpError) => {
        const $error = error;
        $error.isCancelRequest = Axios.isCancel($error);
        // 关闭进度条动画
        NProgress.done();
        // 所有的响应异常 区分来源为取消请求/非取消请求
        return Promise.reject($error);
      }
    );
  }

  /** 通用请求工具函数 */
  public request<T>(
    method: RequestMethods,
    url: string,
    param?: AxiosRequestConfig,
    axiosConfig?: PureHttpRequestConfig
  ): Promise<PureHttpResult<T>> {
    const config = {
      method,
      url,
      ...param,
      ...axiosConfig
    } as PureHttpRequestConfig;

    // 单独处理自定义请求/响应回掉
    return new Promise((resolve, reject) => {
      PureHttp.axiosInstance
        .request(config)
        .then((response: undefined) => {
          resolve(response);
        })
        .catch(error => {
          reject(error);
        });
    });
  }

  /** 单独抽离的post工具函数 */
  public post<T, P>(
    url: string,
    params?: T,
    config?: PureHttpRequestConfig
  ): Promise<P> {
    return this.request<P>("post", url, params, config);
  }

  /** 单独抽离的get工具函数 */
  public get<T, P>(
    url: string,
    params?: T,
    config?: PureHttpRequestConfig
  ): Promise<P> {
    return this.request<P>("get", url, params, config);
  }
}

export const http = new PureHttp();
